# -*- coding: utf-8 -*-

#  This file is part of GLExPIB.
#
#  GLExPIB is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  GLExPIB is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU Lesser General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with GLExPIB.  If not, see <http://www.gnu.org/licenses/>.

import ctypes, ctypes.util

def _load_lib():
	path = ctypes.util.find_library("glexpib") or "./libglexpib.so"
	try:
		lib = ctypes.CDLL(path)
	except:
		raise StandardError("Couldn't load the libglexpib C library")
	return lib

_lib = _load_lib()
_glexpib_init = _lib["glexpib_init"]
_glexpib_init.argtypes = [
	ctypes.c_void_p,
	ctypes.c_uint16,
	ctypes.c_uint8
	]
_glexpib_quit = _lib["glexpib_quit"]
_glexpib_quit.argtypes = [
	ctypes.c_void_p
	]
_glexpib_writeString = _lib["glexpib_writeString"]
_glexpib_writeString.argtypes = [
	ctypes.c_void_p,
	ctypes.c_uint8,
	ctypes.c_char_p,
	ctypes.c_size_t
	]
_glexpib_readString = _lib["glexpib_readString"]
_glexpib_readString.argtypes = [
	ctypes.c_void_p,
	ctypes.c_uint8,
	ctypes.c_char_p,
	ctypes.c_void_p,
	ctypes.c_size_t
	]
_glexpib_setRespTimeout = _lib["glexpib_setRespTimeout"]
_glexpib_setRespTimeout.argtypes = [
	ctypes.c_void_p,
	ctypes.c_uint32,
	]
_glexpib_setBusTimeout = _lib["glexpib_setBusTimeout"]
_glexpib_setBusTimeout.argtypes = [
	ctypes.c_void_p,
	ctypes.c_uint32,
	]
_glexpib_strerror = _lib["glexpib_strerror"]
_glexpib_strerror.restype = ctypes.c_char_p

def _get_errordict():
	errs = dict()
	i = 1
	while True:
		r = _glexpib_strerror(i)
		if not r:
			return errs
		errs[i] = r
		i += 1

class PPGPIB(object):
	DEFAULT_READ_TIMEOUT = 1.0
	global _glexpib_init
	global _glexpib_quit
	global _glexpib_readString
	global _glexpib_writeString
	global _glexpib_setRespTimeout
	global _glexpib_setBusTimeout
	class Error(StandardError):
		_errordict = _get_errordict()
		def __init__(self, i):
			StandardError.__init__(self, self._errordict[i])
	def __init__(self, base_port=0x378, my_addr=1):
		self._context = ctypes.c_void_p(None)
		r = _glexpib_init(ctypes.byref(self._context), base_port, my_addr)
		if r:
			self._context = None
			raise self.Error(r)
		self.set_resp_timeout(self.DEFAULT_READ_TIMEOUT)
	def write(self, addr, data, timeout = None):
		if timeout:
			old_timeout = self._resp_timeout
			self.set_resp_timeout(timeout)
		r = _glexpib_writeString(self._context, addr, data, len(data))
		if timeout:
			self.set_resp_timeout(old_timeout)
		if r:
			raise self.Error(r)
	def set_resp_timeout(self, x):
		self._resp_timeout = x
		_glexpib_setRespTimeout(self._context, int(self._resp_timeout * 1e6))
	def read(self, addr, max_length = 1024, timeout = None):
		if timeout:
			old_timeout = self._resp_timeout
			self.set_resp_timeout(timeout)
		len_ = ctypes.c_size_t(0)
		data = ctypes.create_string_buffer(max_length)
		r = _glexpib_readString(self._context, addr, data, ctypes.byref(len_),
			 max_length)
		if timeout:
			self.set_resp_timeout(old_timeout)
		if r:
			raise self.Error(r)
		return data.raw[:int(len_.value)].strip("\x00\r\n")
	def close(self):
		if self._context:
			_glexpib_quit(self._context)
			self._context = None
	def __del__(self):
		self.close()
